﻿/// ZaxControls
/// Programmed by Leland Ede
/// Website: http://www.zaxisstudios.com
/// E-Mail: codeplex@zaxis-studios.com
/// Create: 4/01/2014
/// Modified: 4/09/2014

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using ZaxLib.Web.Writers.Nodes;
using ZaxLib.Web.UI.Events;

namespace ZaxLib.Web.UI.WebControls
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:ListView ListItems= runat=server />")]
    public class ListView : ZaxControl
    {
		// TODO: Add form values so that lists can be posted back to the server to save changes

		#region ListView Data Structures

		public enum ListViewType
		{
			LVT_NONE,
			LVT_BULLET,
			LVT_DRAGGABLE,
			LVT_NUMBERED,
			LVT_RADIO,
			LVT_CHECKBOX,
			LVT_SORT,
			LVT_SELECT,
			LVT_DROPDOWN,
			LVT_MULTIDROPDOWN,
			LVT_YESNO
		}

		private class ItemNode
		{
			public String key;
			public String value;

			public ItemNode(String inKey, String inValue)
			{
				key = inKey;
				value = inValue;
			}

			public override string ToString()
			{
				return value;
			}
		}

		private class ItemComparer : IComparer
		{
			public int Compare(Object o1, Object o2)
			{
				ItemNode item1 = o1 as ItemNode;
				ItemNode item2 = o2 as ItemNode;
				if (item1 == null || item2 == null)
				{
					throw new Exception("Can't cast Object to ItemNode");
				}
				return String.Compare(item1.value, item2.value);
			}

			public int Compare(ItemNode item1, String item2)
			{
				return String.Compare(item1.value, item2);
			}
		}

		#endregion

		#region Parameters

		[Bindable(true)]
		[Category("Data")]
		[DefaultValue("")]
		[Localizable(true)]
		public virtual String ListItems
		{
			get
			{
				String s = ViewState["ListItems"] as String;
				return (s == null ? String.Empty : s);
			}
			set
			{
				ViewState["ListItems"] = value;
			}
		}

		[Bindable(false)]
		[Category("Data")]
		[DefaultValue("false")]
		[Localizable(true)]
		public bool AutoSort
		{
			get
			{
				bool b = Convert.ToBoolean(ViewState["AutoSort"]);
				return b;
			}
			set
			{
				ViewState["AutoSort"] = value;
			}
		}

		[Bindable(true)]
		[Category("Appearance")]
		[DefaultValue("")]
		[Localizable(true)]
		public String ListType
		{
			get
			{
				String s = ViewState["ListType"] as String;
				return (s == null ? "UnOrdered" : s);
			}
			set
			{
				ViewState["ListType"] = value;
			}
		}

		public ListViewType Type
		{
			get
			{
				return ToListViewType(ListType);
			}
		}

		[Bindable(true)]
		[Category("Appearance")]
		[DefaultValue("")]
		[Localizable(true)]
		public String SortClass
		{
			get
			{
				String s = ViewState["SortClass"] as String;
				return (s == null ? "sortable" : s);
			}
			set
			{
				ViewState["SortClass"] = value;
			}
		}

		[Bindable(true)]
		[Category("Appearance")]
		[DefaultValue("")]
		[Localizable(true)]
		public String SelectClass
		{
			get
			{
				String s = ViewState["SelectClass"] as String;
				return (s == null ? "selectable" : s);
			}
			set
			{
				ViewState["SelectClass"] = value;
			}
		}

		public String ListManagerID
		{
			get
			{
				String s = String.Format("{0}_listManager", ID);
				if (ViewState["ListManagerID"] != null)
				{
					s = ViewState["ListManagerID"].ToString();
				}

				return s;
			}
			set
			{
				ViewState["ListManagerID"] = value;
			}
		}

		private ListViewType ToListViewType(String type)
		{
			ListViewType lvType = ListViewType.LVT_NONE;
			switch (type.ToUpper())
			{
				case "BULLET":
				case "UNORDERED":
					{
						lvType = ListViewType.LVT_BULLET;
					}
					break;
				case "DRAGGABLE":
					{
						lvType = ListViewType.LVT_DRAGGABLE;
					}
					break;
				case "CHECKBOX":
					{
						lvType = ListViewType.LVT_CHECKBOX;
					}
					break;
				case "DROPDOWN":
					{
						lvType = ListViewType.LVT_DROPDOWN;
					}
					break;
				case "MULTI":
				case "MULTIPLE":
				case "MULTISELECT":
				case "MILTIDROPDOWN":
					{
						lvType = ListViewType.LVT_MULTIDROPDOWN;
					}
					break;
				case "NUMBERED":
				case "ORDERED":
					{
						lvType = ListViewType.LVT_NUMBERED;
					}
					break;
				case "RADIO":
					{
						lvType = ListViewType.LVT_RADIO;
					}
					break;
				case "SORT":
					{
						lvType = ListViewType.LVT_SORT;
					}
					break;
				case "SELECT":
					{
						lvType = ListViewType.LVT_SELECT;
					}
					break;
				case "YESNO":
					{
						lvType = ListViewType.LVT_YESNO;
					}
					break;
			}

			return lvType;
		}

		private ArrayList _items = null;
		/// <summary>
		/// List of items to draw in UL/OL list
		/// </summary>
		[Browsable(false)]
		public virtual ArrayList Items
		{
			get
			{
				if (_items == null)
				{
					_items = new ArrayList();
					if (HasText(ListItems))
					{
						// Break string apart by comma separator
						String[] list = ListItems.Split(',');
						// Pull each element out of array and store in ArrayList
						foreach (String item in list)
						{
							AddItem(item.Trim());
						}
					}
				}// Endif _items is null

				return _items;
			}
		}// End parameter Items

		#endregion

		#region Constructors

		public ListView()
			: base()
		{
			HelpPosition = "AfterLabel";
		}

		#endregion

		#region Control Writers

		protected override void ControlWrite(HtmlTextWriter writer)
		{
			// Process base class Control Write
			base.ControlWrite(writer);
			switch (Type)
			{
				case ListViewType.LVT_BULLET:
					{
						ListWrite(writer);
					}
					break;
				case ListViewType.LVT_DRAGGABLE:
					{
						DraggableWrite(writer);
					}
					break;
				case ListViewType.LVT_MULTIDROPDOWN:
				case ListViewType.LVT_DROPDOWN:
					{
						DropdownWrite(writer);
					}
					break;
				case ListViewType.LVT_RADIO:
					{
						RadioWrite(writer);
					}
					break;
				case ListViewType.LVT_SELECT:
					{
						SelectWrite(writer);
					}
					break;
				case ListViewType.LVT_SORT:
					{
						SortWrite(writer);
					}
					break;
				case ListViewType.LVT_YESNO:
					{
						YesNoWrite(writer);
					}
					break;
			}
			// Check if there are items to draw
		}// End method ControlWrite

		protected virtual void DraggableWrite(HtmlTextWriter writer)
		{
			if (Items.Count > 0)
			{
				// Render 
				writer.RenderBeginTag(HtmlTextWriterTag.Div);
				writer.Flush();

				writer.AddAttribute(HtmlTextWriterAttribute.Id, ID);
				writer.RenderBeginTag(HtmlTextWriterTag.Ul);

				if (AutoSort)
				{
					Items.Sort(new ItemComparer());
				}

				// Draw each element
				foreach (ItemNode item in Items)
				{
					// Check if CssClass is defined
					if (HasText(CssClass))
					{
						writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
					}
					writer.RenderBeginTag(HtmlTextWriterTag.Li);
					writer.Write(item.value);
					// Render LI end tag
					writer.RenderEndTag();
					writer.WriteLine("");
				}
				// Render End UL tag
				writer.RenderEndTag();
				// Render end DIV tag
				writer.RenderEndTag();

				// Clear writer cache
				writer.Flush();

				// Make the list draggable
				INode node = CodeWriter.CreateReadyFunction();
				CodeWriter.AddChild(String.Format("\"#{0} li\"", ID), node).Selector();
				CodeWriter.AddChild("draggable").Joined();
				node = CodeWriter.AddParam("").ObjectDef();
				CodeWriter.AddParam("revert", "\"invalid\"", node).VarDef();
			}// Endif Items.Count is greater than 0

		}// End method DraggableWrite

		protected virtual void ListWrite(HtmlTextWriter writer)
		{
			if (Items.Count > 0)
			{
				// Check if CssClass is defined
				if (HasText(CssClass))
				{
					writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
				}
				// Render 
				writer.RenderBeginTag(HtmlTextWriterTag.Div);
				writer.Flush();

				writer.AddAttribute(HtmlTextWriterAttribute.Id, ID);
				if (String.Compare(ListType, "Ordered") == 0)
				{
					writer.RenderBeginTag(HtmlTextWriterTag.Ol);
				}
				else
				{
					writer.RenderBeginTag(HtmlTextWriterTag.Ul);
				}

				if (AutoSort)
				{
					Items.Sort(new ItemComparer());
				}

				// Draw each element
				foreach (ItemNode item in Items)
				{
					writer.RenderBeginTag(HtmlTextWriterTag.Li);
					writer.Write(item.value);
					writer.RenderEndTag();
					writer.WriteLine("");
				}
				writer.RenderEndTag();
				writer.RenderEndTag();
			}
		}

		protected virtual void SortWrite(HtmlTextWriter writer)
		{
			writer.AddAttribute(HtmlTextWriterAttribute.Class, SortClass);

			ListWrite(writer);

			InputWrite(writer);
			INode top = CodeWriter.CreateTopNode();
			CodeWriter.AddChild(ID).SelectorId();
			CodeWriter.AddChild("sortable").Joined();
			CodeWriter.AddParam("");
			CodeWriter.AddChild(ID, top).SelectorId();
			CodeWriter.AddChild("disableSelection").Joined();
			CodeWriter.AddParam("");
		}

		protected virtual void SelectWrite(HtmlTextWriter writer)
		{
			writer.AddAttribute(HtmlTextWriterAttribute.Class, SelectClass);

			ListWrite(writer);

			InputWrite(writer);
			INode top = CodeWriter.CreateTopNode();
			CodeWriter.AddChild(ID).SelectorId();
			CodeWriter.AddChild("selectable").Joined();
			if (IsClicked)
			{
				INode node = CodeWriter.AddParam("").ObjectDef();
				node = CodeWriter.AddParam("selected", node).VarDef();
				CodeWriter.AddChild("function", node).Function();
				CodeWriter.AddParam("event");
				CodeWriter.AddParam("ui");
				// Move the value from what was clicked to the input box
				CodeWriter.AddChild(String.Format("\t$(\"input[name={0}]\").value = ui.selected.innerHTML;", ListManagerID)).RawCode();
				CodeWriter.AddChild(String.Format("\t__doPostBack(\"{0}\", \"{1}[\" + ui.selected.innerHTML + \"]\");", UniqueID, CLICKED)).RawCode();
			}
			else
			{
				CodeWriter.AddParam("");
			}
		}

		protected virtual void RadioWrite(HtmlTextWriter writer, bool NewLine = true)
		{
			writer.Flush();
			if (Items.Count > 0)
			{
				String[] selected = Text.Replace(", ", ",").Split(',');
				ArrayList list = new ArrayList(selected);
				String ChangeClass = String.Format("{0}{1}", ID, "Change");
				foreach (ItemNode item in Items)
				{
					writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
					writer.AddAttribute(HtmlTextWriterAttribute.Value, item.key);
					writer.AddAttribute(HtmlTextWriterAttribute.Type, "Radio");
					writer.AddAttribute(HtmlTextWriterAttribute.Class, ChangeClass);
					if (list.IndexOf(item.key) >= 0)
					{
						writer.AddAttribute(HtmlTextWriterAttribute.Checked, "checked");
					}
					writer.RenderBeginTag(HtmlTextWriterTag.Input);
					writer.RenderEndTag();
					writer.WriteLine(item.value);
					if (NewLine)
					{
						writer.WriteBreak();
					}
					writer.Flush();
				}

				if (IsChange)
				{
					INode node = CodeWriter.CreateReadyFunction();
					CodeWriter.AddChild(ChangeClass, node).SelectorClass();
					CodeWriter.AddChild("change", node).Joined();
					node = CodeWriter.AddParam("function").Function();
					String PostBackCode = String.Format("__doPostBack(\"{0}\",\"{1}[]\");", UniqueID, CHANGED);
					CodeWriter.AddChild(PostBackCode, node).RawCode();
				}
			}
		}

		protected virtual void DropdownWrite(HtmlTextWriter writer)
		{
			if (Type == ListViewType.LVT_MULTIDROPDOWN)
			{
				writer.AddAttribute(HtmlTextWriterAttribute.Multiple, "multiple");
			}
			writer.AddAttribute(HtmlTextWriterAttribute.Id, UniqueID);
			writer.RenderBeginTag(HtmlTextWriterTag.Select);
			writer.Flush();
			if (Items.Count > 0)
			{
				String[] selected = Text.Replace(", ", ",").Split(',');
				ArrayList list = new ArrayList(selected);
				foreach (ItemNode item in Items)
				{
					writer.AddAttribute(HtmlTextWriterAttribute.Value, item.key);
					if (list.IndexOf(item.key) >= 0)
					{
						writer.AddAttribute(HtmlTextWriterAttribute.Selected, "Selected");
					}
					writer.RenderBeginTag(HtmlTextWriterTag.Option);
					writer.Write(item.value);
					writer.RenderEndTag();
					writer.WriteLine();
					writer.Flush();
				}
			}

			writer.RenderEndTag();

		}

		protected virtual void InputWrite(HtmlTextWriter writer)
		{
			writer.Flush();
			writer.AddAttribute(HtmlTextWriterAttribute.Id, UniqueID);
			writer.AddAttribute(HtmlTextWriterAttribute.Type, "hidden");
			writer.AddAttribute(HtmlTextWriterAttribute.Name, ListManagerID);
			writer.AddAttribute(HtmlTextWriterAttribute.Value, Text);
			writer.RenderBeginTag(HtmlTextWriterTag.Input);
			writer.RenderEndTag();
			writer.Flush();
		}// End method InputWriter

		/// <summary>
		/// Create a yes/no question
		/// </summary>
		/// <param name="writer"></param>
		protected virtual void YesNoWrite(HtmlTextWriter writer)
		{
			Items.Clear();
			AddItem("YES", "Yes");
			AddItem("NO", "No");
			RadioWrite(writer, false);
		}

		#endregion

		#region Render Methods

		protected override void Render(HtmlTextWriter writer)
		{
			PostBackOptions pbo = new PostBackOptions(this);
			base.Render(writer);
		}

		protected override void RenderContents(HtmlTextWriter writer)
		{
			switch (Type)
			{
				case ListViewType.LVT_RADIO:
					{
						lblType = LabelType.LT_TOP;
					}
					break;
			}
			base.RenderContents(writer);
		}

		#endregion

		#region Data Methods

		public void AddItem(String key, String item)
		{
			// Make sure _items is defined
			if (_items == null)
			{
				int tVal = Items.Count;
			}

			ItemNode node = new ItemNode(key, item);
			_items.Add(node);

		}

		public void AddItem(String item)
		{
			AddItem(item, item);
		}

		public void Clear()
		{
			if (_items != null)
			{
				_items.Clear();
			}
		}

		#endregion

		#region Events

		public event EventHandler Click;
		[Browsable(false)]
		public bool IsClicked
		{
			get
			{
				return Click != null;
			}
		}

		public virtual void OnClick(EventArgs e)
		{
			if (IsClicked)
			{
				Click(this, e);
			}
		}

		public override void RaisePostDataChangedEvent()
		{
			base.RaisePostDataChangedEvent();
			OnClick(EventArgs.Empty);
		}

		public override void RaisePostBackEvent(String eventArgs)
		{
			base.RaisePostBackEvent(eventArgs);
			// Set the selected item in object
			Text = eventArgs;
			ControlEventArgs e = new ControlEventArgs(eventArgs);
			OnClick(e);
		}

		#endregion
	}

}// End namespace ZaxLib.Web.UI.WebControls
